
package DAO;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author HuuTri
 * class cung cấp các hàm cơ bản phục vụ cho giao tiếp với SQL Server
 */
public class SQLHelperDAO {
    private static Connection _connection = null; // biến kết nối đến server
    private static String _username = "sa"; // Tên đăng nhập vào server
    private static String _password = " "; // Mật khẩu đăng nhập vào server
    private static String _url = "jdbc:sqlserver://localhost:1433; databaseName=QuanLyDaiLy"; // chuỗi kết nối vào server
    
    /*Thực thi procedure trả về bảng kết quả*/
    public static DefaultTableModel execQuery(String procName, List<Parameter> listParams) {
        DefaultTableModel tableModel = new DefaultTableModel();
        try {
            openConnection(); // Mở kết nối với Database
            int numOfParams = 0; // Lấy số lượng tham số của prcedure
            if (listParams != null) {
                numOfParams  = listParams.size();
            }           
            String paramsFormat = getProcParamsFormat(numOfParams); // Lấy định đạng được truyền vào hàm
            String statement = String.format("{ call %s(%s) }", procName, paramsFormat);
            
            CallableStatement callableStament = _connection.prepareCall(statement);
            for (int i = 0; i < numOfParams; i++) {
                // Thiết lập các tham số cho lời goi procedure
               callableStament.setObject(
                       i + 1, 
                       listParams.get(i).getValue()
                       );
            }
            ResultSet res = callableStament.executeQuery();// Lấy kết quả của câu lệnh thực thi
            ResultSetMetaData metaData = res.getMetaData(); // Lấy thông tin cần thiết của kết quả trả về
            int totalCol = metaData.getColumnCount(); // Lấy số lượng cột của kết quả trả về.
            Object[] dataRow = new Object[totalCol];
            
            if (res != null) {
                for (int i = 0; i < totalCol; i++) {
                    tableModel.addColumn(metaData.getColumnName(i+1)); // Chèn vào tên cột 
                }
                while (res.next()) { // Duyệt tuần tự các kết quả trả về sau khi thực thi procedure
                    for (int i = 1; i <= totalCol; i++) { // Chèn lần lượt các giá trị của một record
                        dataRow[i - 1] = res.getObject(i);
                    }
                    tableModel.addRow(dataRow); // Chèn dòng vào table
                }               
            }
            
            // Đóng các kết nối nhỏ hiện tại
            res.close();
            callableStament.close();
            
        } catch (Exception ex) {
            int stop = 1;
        } finally {
            closeConnection(); // Đóng kết nối với Database
        }
        
        return tableModel; // Trả về giá trị bảng bị thay đổi.
    }
    
     /*Thực thi procedure không trả về kết quả*/
    public static boolean execNonQuery(String procName, List<Parameter> listParams) {
        boolean res = false; // Biến kiểm tra kết quả
        try {
            openConnection(); // Mở kết nối với Database
            
            int numOfParams = listParams.size(); // Lấy số lượng param truyền vào hàm.
            String paramsFormat = getProcParamsFormat(numOfParams); // Lấy định dạng chuỗi tham số.
            String statement = String.format("{ call %s(%s)}", procName, paramsFormat); // Chuỗi chứa câu lệnh gọi procedure
            
            CallableStatement callableStatement = (CallableStatement) _connection.prepareCall(statement); // Khởi tạo biến gọi procedure thực thi
            if (listParams != null) //Nếu list Param không rỗng sẽ thực hiện
            for (int i = 1; i <= numOfParams; i++) {
                callableStatement.setObject(
                        i, // vị trí của tham số trong câu lệnh call
                        listParams.get(i-1).getValue()
                        ); // Truyền tham số vào câu lệnh call
            }
            
            res = callableStatement.execute(); // Gọi thực thi procedure
            callableStatement.close();
        } catch (Exception ex) {
            int i = 1;
        } finally {
            closeConnection(); // Đóng kết nối Database
        }
        
        return res; // Nếu kết quả bằng 0 thì hàm thực thi thất bại
    }
    
    /*Thực thi procedure trả về 1 giá trị*/
    public static Object execQueryReturnValue(String procName, List<Parameter> listParams) {
        Object res = null;
        try {
            openConnection(); // mở kết nối 
            int numOfParams = listParams.size(); // Lấy số lượng tham số
            String formatParams = getProcParamsFormat(numOfParams); // Lâý định dạng danh sách tham số
            String statement = String.format("{?=call %s(%s)}", procName, formatParams);
            
            CallableStatement callableStatement = _connection.prepareCall(statement); // Lấy dối tượng callable của connection
            callableStatement.registerOutParameter(1, Types.INTEGER); // Lấy giá trị trả về
            if (listParams != null) {
                for (int i = 1; i <= numOfParams; i++) {
                    callableStatement.setObject(
                            i + 1, // Vị trí tham số trong lời gọi procedure
                            listParams.get(i - 1).getValue() // get giá trị tham số
                            );
                }
            }
            
            callableStatement.execute();
            res  = callableStatement.getObject(1);
            
        } catch (SQLException ex) {
            Logger.getLogger(SQLHelperDAO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            closeConnection(); // đóng kết nối
        }
        
        return res; // Trả về giá trị thực thi của procedure
    }
    
     /* Mở kết nối đến SQL Server */
    private static boolean openConnection() {
        try {
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); // Mở driver kết nối
            _connection = DriverManager.getConnection(_url, _username, _password); // Tạo kết nối đến SQL Server
            
            return true; // Thông báo kết nối thành công
        } catch (ClassNotFoundException | SQLException ex) {
            Logger.getLogger(SQLHelperDAO.class.getName()).log(Level.SEVERE, null, ex);
            return false; // Thông báo kết nối thất bại
        }
    }
    
    /* Đóng kết nối */
    private static boolean closeConnection() {
        if (_connection != null) {
            try {
                _connection.close(); // Đóng kết nối
            } catch (SQLException ex) {
                Logger.getLogger(SQLHelperDAO.class.getName()).log(Level.SEVERE, null, ex);
                return false; // Đóng kết nối thất bại
            }
        }
        return true; // Đóng kết nối thành công
    }    
    
    /*Lấy chuỗi định dạng tham số*/
    private static String getProcParamsFormat(int numOfParams) {
        String res = "";
        
        for( int i = 0; i < numOfParams; i++) {
            res += "?,";
        }
        // Cắt bỏ dấu phẩy cuối cùng tồn tại
        if (res.endsWith(",")) {
            res = res.substring(0, res.length() - 1);
        }
        return res; // Trả về giá trị định dạng của tham số
    }
}
